package com.ruoyi.business.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.ruoyi.bizsys.domain.*;
import com.ruoyi.bizsys.enums.BankStatusEnum;
import com.ruoyi.bizsys.enums.CustCardStatusEnum;
import com.ruoyi.bizsys.enums.RealNameStatusEnum;
import com.ruoyi.bizsys.enums.UserStatusEnum;
import com.ruoyi.bizsys.mapper.AppUserMapper;
import com.ruoyi.bizsys.mapper.BankAccountMapper;
import com.ruoyi.bizsys.mapper.CustBankCardMapper;
import com.ruoyi.bizsys.mapper.RealNameAuthMapper;
import com.ruoyi.bizsys.service.IAppDeviceFingerprintService;
import com.ruoyi.bizsys.service.IAppDeviceInfoService;
import com.ruoyi.bizsys.service.IAppUserReasonService;
import com.ruoyi.bizsys.service.IExtGpsService;
import com.ruoyi.business.service.IAppService;
import com.ruoyi.business.service.IBusinessService;
import com.ruoyi.business.service.IWalletService;
import com.ruoyi.common.VersionUtils;
import com.ruoyi.common.config.ServerYml;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.constant.WalletConstants;
import com.ruoyi.common.enums.RspEnmu;
import com.ruoyi.common.exception.BusinessException;
import com.ruoyi.common.utils.Func;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.sign.Md5Utils;
import com.ruoyi.extdata.service.IExternalApiService;
import com.ruoyi.system.mapper.SysDictDataMapper;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysDictDataService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * @Author: Jamnsin
 * @Date: 2021/4/8 4:53 下午
 */
@Slf4j
@Service
@EnableAsync
public class AppServiceImpl implements IAppService {

    @Autowired
    IAppDeviceInfoService appDeviceInfoService;

    @Autowired
    IExternalApiService externalApiService;

    @Autowired
    ISysDictDataService sysDictDataService;

    @Autowired
    IExtGpsService extGpsService;

    @Autowired
    ISysConfigService sysConfigService;

    @Autowired
    AppUserMapper appUserMapper;

    @Autowired
    private IBusinessService businessService;

    @Autowired
    private IAppDeviceFingerprintService fingerprintService;

    @Autowired
    private RealNameAuthMapper realNameAuthMapper;

    @Autowired
    private IAppUserReasonService appUserReasonService;

    @Autowired
    private SysDictDataMapper sysDictDataMapper;

    @Autowired
    private BankAccountMapper bankAccountMapper;

    @Autowired
    private CustBankCardMapper custBankCardMapper;

    @Autowired
    IWalletService walletService;

    @Override
    public void saveAppDeviceInfoBoard(String userUuid, String custNo, String actionType, String actionKey, JSONObject deviceInfo) {
        saveAppDeviceInfo(userUuid, custNo, actionType, actionKey, deviceInfo);
    }

    @Async("threadPoolTaskExecutor")
    @Override
    public void saveAppDeviceInfo(String userUuid, String custNo, String actionType, String actionKey, JSONObject deviceInfo) {
        log.info("saveAppDeviceInfo:{}", deviceInfo.toString());
        if (null == deviceInfo) {
            log.info("deviceInfo is null");
            throw new BusinessException(RspEnmu.GPS_CHECK_FAILED);
        }

        AppDeviceInfo appDeviceInfo = JSONObject.toJavaObject(deviceInfo, AppDeviceInfo.class);
        appDeviceInfo.setUserId(userUuid);
        appDeviceInfo.setActionType(actionType);
        appDeviceInfo.setCreateTime(new Date());
        appDeviceInfo.setState(UserConstants.NORMAL);

        if (StringUtils.isNotBlank(custNo)) {
            appDeviceInfo.setCustNo(custNo);
        }
        if (StringUtils.isNotBlank(actionKey)) {
            appDeviceInfo.setActionKey(actionKey);
        }

        //更新地理位置
        if (!Func.hasEmpty(appDeviceInfo.getLatitude(), appDeviceInfo.getLongitude())) {

            appDeviceInfo.setLatitude(appDeviceInfo.getLatitude().replace(",", "."));
            appDeviceInfo.setLongitude(appDeviceInfo.getLongitude().replace(",", "."));

            BigDecimal longitude = new BigDecimal(appDeviceInfo.getLongitude()).setScale(4, BigDecimal.ROUND_DOWN);
            BigDecimal latitude = new BigDecimal(appDeviceInfo.getLatitude()).setScale(4, BigDecimal.ROUND_DOWN);
            log.debug("待处理的经纬度，longitude = {}, latitude = {}", longitude, latitude);

            ExtGps extGps = new ExtGps();
            extGps.setLongitude(longitude.toString());
            extGps.setLatitude(latitude.toString());
            extGps.setState(UserConstants.BUSINESS_NORMAL);
            List<ExtGps> extGps1 = extGpsService.selectExtGpsList(extGps);

            if (extGps1.size() > 0) {
                log.info("本地存在对应GPS经纬度，无需解析");
                extGps = extGps1.get(0);
                appDeviceInfo.setAddress(extGps.getAddress());
                appDeviceInfo.setCountry(extGps.getCountry());
                appDeviceInfo.setCountryState(extGps.getCountryState());
                appDeviceInfo.setCity(extGps.getCity());
                appDeviceInfo.setRegion(extGps.getRegion());
            } else {
                log.info("本地未查找到对应GPS经纬度，需解析");
                try {
                    String geoCodeSwitch = getDictLable("biz_switch", "geo_" + actionType + "_switch");
                    if ("1".equals(geoCodeSwitch)) {
                        JSONObject obj = externalApiService.getGeocode(appDeviceInfo.getLatitude(), appDeviceInfo.getLongitude());
                        if (null != obj) {
                            if (null != obj.get("address")) {
                                appDeviceInfo.setAddress(obj.getString("address"));
                            }
                            if (null != obj.get("country")) {
                                appDeviceInfo.setCountry(obj.getString("country"));
                            }
                            if (null != obj.get("countryState")) {
                                appDeviceInfo.setCountryState(obj.getString("countryState"));
                            }
                            if (null != obj.get("city")) {
                                appDeviceInfo.setCity(obj.getString("city"));
                            }
                            if (null != obj.get("region")) {
                                appDeviceInfo.setRegion(obj.getString("region"));
                            }
                        }
                    }

                    //保存
                    if (StringUtils.isNotBlank(appDeviceInfo.getCountry()) && StringUtils.isNotBlank(appDeviceInfo.getCountryState())) {
                        ExtGps extGpsAdd = new ExtGps();
                        extGpsAdd.setAddress(appDeviceInfo.getAddress());
                        extGpsAdd.setLongitude(longitude + "");
                        extGpsAdd.setLatitude(latitude + "");
                        extGpsAdd.setCity(appDeviceInfo.getCity());
                        extGpsAdd.setCountry(appDeviceInfo.getCountry());
                        extGpsAdd.setRegion(appDeviceInfo.getRegion());
                        extGpsAdd.setCountryState(appDeviceInfo.getCountryState());
                        extGpsService.insertExtGps(extGpsAdd);
                    }

                } catch (Exception e) {
                    log.error("gps异常：", e);
                    saveDeviceInfo(userUuid, appDeviceInfo);
                    throw new BusinessException(RspEnmu.EXT_API_EXCEPTION_GPS);
                }
            }

            String gpsRiskArea = sysConfigService.selectConfigByKey("gps_risk_area");
            if (StringUtils.isNotBlank(appDeviceInfo.getCountryState()) && StringUtils.containsAny(appDeviceInfo.getCountryState(), gpsRiskArea.split(","))) {
                saveDeviceInfo(userUuid, appDeviceInfo);
                log.error("地区限制");
                throw new BusinessException(RspEnmu.GPS_CHECK_FAILED);
            }
        }

        saveDeviceInfo(userUuid, appDeviceInfo);
    }

    private void saveDeviceInfo(String userUuid, AppDeviceInfo appDeviceInfo) {
        appDeviceInfoService.insertAppDeviceInfo(appDeviceInfo);
        String firstVersion = businessService.getDeviceFirstVersion(userUuid);
        //首次提交版本是否小于2.1.2 是则追加app_device_fingerprint的数据
        if (Func.isEmpty(firstVersion) || (Func.isNotEmpty(firstVersion) && VersionUtils.compareVersion(firstVersion, "2.1.2") < 0)) {
            //品牌映射
            String brand = businessService.getDeviceMapper(appDeviceInfo.getPhoneBrand());
            if (Func.isNotEmpty(appDeviceInfo.getPhoneBrand())) {
                String[] split = appDeviceInfo.getPhoneBrand().split(" ");
                appDeviceInfo.setPhoneBrand(split[0]);
            }
            if (Func.isNotEmpty(brand)) {
                appDeviceInfo.setPhoneBrand(brand);
            }
            saveAppDeviceFingerprint(appDeviceInfo);
        }
    }

    @Override
    public void saveAppDeviceFingerprint(AppDeviceInfo device) {

        AppDeviceFingerprint fingerprint = new AppDeviceFingerprint();
        String bf = device.getPhoneBrand() + device.getPhoneModel();
        fingerprint.setAndroidId(device.getFingerprint());
        if (!StringUtils.equalsAny(fingerprint.getAndroidId(), "{}", "", null)) {
            fingerprint.setAndroidFingerprint(Md5Utils.getAndroidNativeMD5(device.getFingerprint() + bf));
        }

        fingerprint.setGaid(device.getGaid());
        if (!StringUtils.equalsAny(fingerprint.getGaid(), "{}", "", null)) {
            fingerprint.setGaidFingerprint(Md5Utils.getAndroidNativeMD5(device.getGaid() + bf));
        }

        fingerprint.setImei(device.getImei());
        if (!StringUtils.equalsAny(fingerprint.getImei(), "{}", "", null)) {
            String imei = device.getImei().split(",")[0];
            fingerprint.setImeiFingerprint(Md5Utils.getAndroidNativeMD5(imei + bf));
        }

        fingerprint.setMac(device.getMac());
        if (!StringUtils.equalsAny(fingerprint.getMac(), "{}", "", null)) {
            fingerprint.setMacFingerprint(Md5Utils.getAndroidNativeMD5(device.getMac() + bf));
        }

        fingerprint.setUuid(device.getUuid());
        if (!StringUtils.equalsAny(fingerprint.getUuid(), "{}", "", null)) {
            fingerprint.setUuidFingerprint(Md5Utils.getAndroidNativeMD5(device.getUuid() + bf));
        }

        fingerprint.setNewFingerprint(device.getNewFingerprint());
        fingerprint.setUserId(device.getUserId());
        fingerprint.setCreateTime(new Date());
        fingerprint.setActionType(device.getActionType());

        fingerprintService.insertAppDeviceFingerprint(fingerprint);
    }


    @Override
    public AppUser getValidInviter(String inviteCode) {
        return appUserMapper.getValidInviter(inviteCode);
    }

    @Override
    public void deleteAccount(String custNo, String dictSort, AppUser appUser, String reason) {

        // 修改用户状态和实名信息
        blockUserRelative(appUser.getUserUuid(), custNo);

        // 保存操作理由
        saveReason(dictSort, appUser, reason);
    }

    private void blockUserRelative(String userId, String custNo) {
        // 改变账号状态
        appUserMapper.updateAppUserToCancellation(userId, UserStatusEnum.CANCELLATION.getCode());
        // 改变实名信息状态
        realNameAuthMapper.updateRealNameAuthToCancellation(custNo, RealNameStatusEnum.CANCELLATION.getCode());
        // 修改bank_account状态
        bankAccountMapper.updateStates(custNo, BankStatusEnum.CANCELLATION.getCode());
        // 修改cust_bank_card状态
        custBankCardMapper.updateStates(custNo, CustCardStatusEnum.CANCELLATION.getCode());
        // 冻结钱包
        walletService.blockWallet(custNo, WalletConstants.WALLET_STATUS_LOCK);
    }

    /**
     * 实际修改用户状态和实名信息，保存理由操作
     *
     * @param dictSort 理由
     * @param appUser  用户
     */
    public void saveReason(String dictSort, AppUser appUser, String reason) {
        if (null == reason || StringUtils.isBlank(reason)) {
            //通过字典查理由
            reason = sysDictDataMapper.selectDictValueBySort(dictSort);
        }
        //保存删除理由表
        appUserReasonService.save(new AppUserReason(null, appUser.getUserUuid(), appUser.getPhone(), reason, null, null));
    }

    protected String getDictLable(String dictType, String dictValue) {
        return sysDictDataService.selectDictLabel(dictType, dictValue);
    }

}
